package soul

import (
	"changeme/android"
	"context"
	"github.com/beevik/etree"
	"github.com/wailsapp/wails/v2/pkg/runtime"
	"path"
	"strings"
	"time"
)

type Soul struct {
	ctx context.Context
}

var (
	MatchBtn            []int
	PlantBtn            []int
	SwipeCoordinate     []int
	ChatReturnBtn       []int
	ChatSendBtn         []int
	MsgBtn              []int
	MatchCancelFunc     context.CancelFunc
	HandleMsgCancelFunc context.CancelFunc
)

func (s *Soul) StartUp(c context.Context) {
	s.ctx = c
	android.Log.SetContext(c)
	android.Log.AddPreHook(func(ctx context.Context, logStr string) {
		runtime.EventsEmit(ctx, "append_log", logStr)
	})
}

// Init 初始化某些按钮的坐标
func (s *Soul) Init() (map[string][]int, string) {
	android.Log.Println("start init config...")
	var err string
	if err := android.CheckKeyboard(); err != "" {
		return nil, err
	}
	var doc *etree.Document
	if doc, err = DumpSoul(); err != "" {
		return nil, err
	}
	if err := GetMatchBut(doc); err != "" {
		return nil, err
	}
	if err := GetMsgBtn(doc); err != "" {
		return nil, err
	}
	if err := Swipe(doc); err != "" {
		return nil, err
	}
	android.Tap(SwipeCoordinate)
	android.KeyInput(" ")
	if doc, err = DumpSoul(); err != "" {
		return nil, err
	}
	if err := GetChatReturnEle(doc); err != "" {
		return nil, err
	}
	if err := GetSendMsgEle(doc); err != "" {
		return nil, err
	}
	android.Tap(ChatReturnBtn)
	var m = make(map[string][]int)
	m["MatchBtn"] = MatchBtn
	m["PlantBtn"] = PlantBtn
	m["SwipeCoordinate"] = SwipeCoordinate
	m["ChatReturnBtn"] = ChatReturnBtn
	m["ChatSendBtn"] = ChatSendBtn
	m["MsgBtn"] = MsgBtn
	android.Log.Println("init success!")
	return m, ""
}

func GetMsgBtn(doc *etree.Document) string {
	android.ClearSelectEles()
	android.AllEle(doc.ChildElements(), "resource-id", "cn.soulapp.android:id/main_tab_msg")
	if len(android.SelectEles) <= 0 {
		return "check place"
	}
	MsgBtn = android.GetEleBounds(android.SelectEles[0])
	android.Log.Println("GetMsgBtn:", MsgBtn)
	return ""
}

// GetMatchBut 获取开始匹配按钮
func GetMatchBut(doc *etree.Document) string {
	android.ClearSelectEles()
	android.AllEle(doc.ChildElements(), "resource-id", "cn.soulapp.android:id/main_tab_planet")
	if len(android.SelectEles) <= 0 {
		return "check place"
	}
	bounds := android.GetEleBounds(android.SelectEles[0])
	MatchBtn = []int{bounds[0], bounds[3] - 10}
	PlantBtn = bounds
	android.Log.Println("MatchBtn:", MatchBtn, "PlantBtn:", PlantBtn)
	return ""
}

// Swipe 滑动屏幕 在soul特指消息列表的滑动
func Swipe(doc *etree.Document) string {
	android.ClearSelectEles()
	android.AllEle(doc.ChildElements(), "resource-id", "cn.soulapp.android:id/rl_list")
	if len(android.SelectEles) <= 0 {
		return "check place"
	}
	bounds := android.GetEleBounds(android.SelectEles[0])
	SwipeCoordinate = []int{bounds[0], bounds[5] - 10, bounds[0], bounds[3] + 10}
	android.Log.Println("SwipeCoordinate:", SwipeCoordinate)
	return ""
}

// GetChatReturnEle 获取聊天界面的返回按钮
func GetChatReturnEle(doc *etree.Document) string {
	android.ClearSelectEles()
	android.AllEle(doc.ChildElements(), "resource-id", "cn.soulapp.android:id/item_left_back")
	if len(android.SelectEles) <= 0 {
		return "GetChatReturnEle check place"
	}
	ChatReturnBtn = android.GetEleBounds(android.SelectEles[0])
	android.Log.Println("GetChatReturnEle:", ChatReturnBtn)
	return ""
}

// GetSendMsgEle 获取聊天界面的发送消息按钮
func GetSendMsgEle(doc *etree.Document) string {
	android.ClearSelectEles()
	android.AllEle(doc.ChildElements(), "resource-id", "cn.soulapp.android:id/btn_send")
	if len(android.SelectEles) <= 0 {
		return "GetSendMsgEle check place"
	}
	ChatSendBtn = android.GetEleBounds(android.SelectEles[0])
	android.Log.Println("GetSendMsgEle:", ChatSendBtn)
	return ""
}

// GetOnlyFiveCloseEle 获取仅剩5次警告的关闭按钮
func GetOnlyFiveCloseEle(doc *etree.Document) ([]int, string) {
	android.ClearSelectEles()
	android.AllEle(doc.ChildElements(), "resource-id", "cn.soulapp.android:id/iv_close_bottom")
	if len(android.SelectEles) <= 0 {
		return nil, "GetSendMsgEle check place"
	}
	bounds := android.GetEleBounds(android.SelectEles[0])
	android.Log.Println("GetOnlyFiveCloseEle:", bounds)
	return bounds, ""
}

func DumpSoul() (*etree.Document, string) {
	e := android.Dump()
	if e != "" {
		android.Log.Println(e)
		return nil, e
	}
	doc := etree.NewDocument()
	if err := doc.ReadFromFile(path.Join(android.CurrentPath, "window_dump.xml")); err != nil {
		android.Log.Println(err.Error())
		return nil, err.Error()
	}
	android.Log.Println("DumpSoul success")
	return doc, ""
}

// StartMatch 开始匹配
func (s *Soul) StartMatch(helloMsg string) android.Result {
	ctx, cancelFunc := context.WithCancel(s.ctx)
	MatchCancelFunc = cancelFunc
	android.Log.Println("start match circle...")
	android.Tap(PlantBtn)
	for {
		select {
		case <-ctx.Done():
			android.Log.Println("cancel_match")
			return android.ResultFail("cancel_match")
		default:
			android.Tap(MatchBtn)
			android.Log.Println("start match...")
			var focus string
			var fails int
			for {
				focus = android.CurrentFocus()
				if strings.Contains(focus, "ConversationActivity") {
					break
				}
				fails++
				if fails >= 10 {
					if doc, err := DumpSoul(); err == "" {
						if bounds, err := GetOnlyFiveCloseEle(doc); err == "" {
							android.Tap(bounds)
						} else {
							return android.ResultFail("match timeout")
						}
					} else {
						return android.ResultFail("match timeout")
					}
				}
				time.Sleep(time.Second)
			}
			android.KeyInput(helloMsg)
			android.Tap(ChatSendBtn)
			android.Tap(ChatReturnBtn)
			android.Log.Println("return to new match...")
		}
	}
}

// StopMatch 停止匹配
func (s *Soul) StopMatch() {
	if MatchCancelFunc == nil {
		return
	}
	MatchCancelFunc()
	android.Log.Println("wait for the match stop...")
}

// HandleNewMsg 处理新消息
func (s *Soul) HandleNewMsg() android.Result {
	if android.ApiKey == "" || !android.CheckApiKey() {
		android.Log.Println("please check apiKey: ", android.ApiKey)
		return android.ResultFail("please check apiKey " + android.ApiKey)
	}
	ctx, cancelFunc := context.WithCancel(s.ctx)
	HandleMsgCancelFunc = cancelFunc
	android.Log.Println("start handle new msg...")
	for {
		select {
		case <-ctx.Done():
			android.Log.Println("cancel_handle_new_msg")
			return android.ResultFail("cancel_handle_new_msg")
		default:
			android.Tap(MsgBtn)
			for i := 0; i < 3; {
				if doc, err := DumpSoul(); err == "" {
					if getUnreadMsgTap(doc) {
						bounds := android.GetEleBounds(android.SelectEles[0])
						android.Log.Println("start handle msg...")
						android.Tap(bounds)
						if !strings.Contains(android.CurrentFocus(), "ConversationActivity") {
							android.Log.Println("handle_new_msg failed: check place")
							return android.ResultFail("handle_new_msg failed: check place")
						}
						if docC, err := DumpSoul(); err == "" {
							android.KeyInput(android.HandleMsgGPT(ParseChatMsg(docC)))
						} else {
							android.Log.Println("handle_new_msg failed: check place")
							return android.ResultFail("handle_new_msg failed: check place")
						}
						android.Tap(ChatSendBtn)
						android.Tap(ChatReturnBtn)
					} else {
						i++
						android.Swipe(SwipeCoordinate)
					}
				} else {
					android.Log.Println("handle_new_msg failed: check place")
					return android.ResultFail("handle_new_msg failed: check place")
				}
			}
			swipeReturn := []int{SwipeCoordinate[0], SwipeCoordinate[3], SwipeCoordinate[2], SwipeCoordinate[1]}
			for i := 0; i < 4; i++ {
				android.Swipe(swipeReturn)
			}
		}
	}
}

// StopHandleNewMsg 停止处理新消息
func (s *Soul) StopHandleNewMsg() {
	if HandleMsgCancelFunc == nil {
		return
	}
	HandleMsgCancelFunc()
	android.Log.Println("wait for the handle stop...")
}

// 获取当前页面未读消息的元素 没有则返回false
func getUnreadMsgTap(doc *etree.Document) bool {
	android.ClearSelectEles()
	android.AllEle(doc.ChildElements(), "resource-id", "cn.soulapp.android:id/unread_msg_number")
	return len(android.SelectEles) > 0
}

// ParseChatMsg 获取最新的对方消息
func ParseChatMsg(doc *etree.Document) string {
	android.ClearSelectEles()
	android.AllEle(doc.ChildElements(), "resource-id", "cn.soulapp.android:id/item_root")
	rootEles := android.SelectEles
	var msg string
	if len(rootEles) > 0 {
		for i := len(rootEles) - 1; i >= 0; i-- {
			android.ClearSelectEles()
			android.AllEle(rootEles[i].ChildElements(), "resource-id", "cn.soulapp.android:id/message_read")
			if len(android.SelectEles) > 0 {
				break
			}
			android.AllEle(rootEles[i].ChildElements(), "resource-id", "cn.soulapp.android:id/content_text")
			if len(android.SelectEles) > 0 {
				msg = android.SelectEles[0].SelectAttr("text").Value + "。" + msg
			}
		}
	}
	android.Log.Println("get new msg: ", msg)
	return msg
}

func (s *Soul) SetApikey(key string) {
	android.ApiKey = key
	android.Log.Println("setApiKey ", android.ApiKey)
}
